/*
 *  geometry.c
 *  wolf3d
 *
 *  Created by James Weatherley on 02/11/2009.
 *  Copyright 2009 James Weatherley. All rights reserved.
 *
 */

#import "geometry.h"

#define SAME_CLOCKNESS 1
#define DIFF_CLOCKNESS 0


# pragma mark Normals
void calculateNormal(const vec3_t a,  const vec3_t b,  const vec3_t c,  vec3_t normal)
{
	vec3_t ab;
	vec3_t bc;
	vectorSubtract(b, a, ab);
	vectorSubtract(c, b, bc);
	vectorCrossProduct(ab, bc, normal);
	_VectorNormalize(normal);
}

#pragma mark Triangle Intersect Stuff
// http://www.angelfire.com/fl/houseofbartlett/solutions/line2tri.html
int checkSameClockDir(vec3_t a, vec3_t b, vec3_t c, vec3_t norm)
{  	
	vec3_t ab;
	vec3_t bc;
	vec3_t cross;
	vectorSubtract(b, a, ab);
	vectorSubtract(c, b, bc);
	vectorCrossProduct(ab, bc, cross);
	_VectorNormalize(cross);
	// Dot product with triangle normal
	float dotprod = DotProduct(cross, norm);
	
	//answer
	if(dotprod < 0) {
		return DIFF_CLOCKNESS;
	} 
	return SAME_CLOCKNESS;
}

int intersectPolygon(vec3_t *vertices, int count, vec3_t intersect, vec3_t normal)
{
	int sameClock = 1;
	
	for(int i = 0; i < count - 1; ++i) {
		sameClock &= checkSameClockDir(vertices[i], vertices[i+1], intersect, normal) == SAME_CLOCKNESS;
		if(!sameClock) {
			break;
		}
	}
	sameClock &= checkSameClockDir(vertices[count-1], vertices[0], intersect, normal) == SAME_CLOCKNESS;
	return sameClock;
}

int intersectPlane(const vec3_t planePoint, const vec3_t planeNormal, 
				   const vec3_t rayOrigin, const vec3_t rayDirection, 
				   vec3_t intersect)
{
	int intersects = 0;
	vec3_t planePointToRayOrigin;
	vectorSubtract(rayOrigin, planePoint, planePointToRayOrigin);
	
	float numerator = DotProduct(planeNormal, planePointToRayOrigin);
	float denominator = DotProduct(planeNormal, rayDirection);
	
	if(denominator) {
		float t = -(numerator / denominator);
		intersect[0] = rayOrigin[0] + rayDirection[0] * t;
		intersect[1] = rayOrigin[1] + rayDirection[1] * t;
		intersect[2] = rayOrigin[2] + rayDirection[2] * t;
		intersects = 1;
	}
	return intersects;
}

int intersectBox(const vec3_t boxMin, const vec3_t boxMax, const vec3_t point, const vec3_t direction)
{
	// http://tog.acm.org/resources/GraphicsGems/gems/RayBox.c
	static const int NUMDIM	= 3;
	static const int RIGHT  = 0;
	static const int LEFT   = 1;
	static const int MIDDLE = 2;
	
	int hit = 0;
	int inside = 1;
	int quadrant[NUMDIM];
	int i;
	int whichPlane;
	vec3_t maxT;
	vec3_t candidatePlane;
	
	/* Find candidate planes; this loop can be avoided if
	 rays cast all from the eye(assume perpsective view) */
	for(i = 0; i < NUMDIM; ++i)
		if(point[i] < boxMin[i]) {
			quadrant[i] = LEFT;
			candidatePlane[i] = boxMin[i];
			inside = 0;
		} else if (point[i] > boxMax[i]) {
			quadrant[i] = RIGHT;
			candidatePlane[i] = boxMax[i];
			inside = 0;
		} else{
			quadrant[i] = MIDDLE;
		}
	
	/* Ray origin inside bounding box */
	if(inside)	{
		hit = 1;
	} else {
		/* Calculate T distances to candidate planes */
		for(i = 0; i < NUMDIM; i++) {
			if(quadrant[i] != MIDDLE && direction[i] != 0.0f) {
				maxT[i] = (candidatePlane[i] - point[i]) / direction[i];
			} else {
				maxT[i] = -1.0f;
			}
		}
		
		/* Get largest of the maxT's for final choice of intersection */
		whichPlane = 0;
		for(i = 1; i < NUMDIM; i++) {
			if(maxT[whichPlane] < maxT[i]) {
				whichPlane = i;
			}
		}
		
		/* Check final candidate actually inside box */
		if(maxT[whichPlane] < 0.0f) {
			hit = 0;
		} else {
			hit = 1;
			vec3_t coord;
			for (i = 0; i < NUMDIM; i++) {
				if(whichPlane != i) {
					coord[i] = point[i] + maxT[whichPlane] * direction[i];
					if(coord[i] < boxMin[i] || coord[i] > boxMax[i]) {
						hit = 0;
						break;
					}
				} else {
					coord[i] = candidatePlane[i];
				}
			}
		}
	}
	
	return hit;
}
